package population.phaseExecutors;

import java.util.ArrayList;
import java.util.Random;

import character.Character;
import character.Gender;
import character.SocialLinks;
import character.race.Race;
import character.race.RaceProperties;
import population.Population;
import population.populationFindPredicates.FindAgeRange;
import population.populationFindPredicates.FindAllButSpecificCharacter;
import population.populationFindPredicates.FindGender;
import population.populationFindPredicates.FindRace;
import population.populationFindPredicates.FindRandom;
import population.populationFindPredicates.FindSocialLink;
import population.populationFindPredicates.PopulationFindPredicate;
import utilities.TimeProperties;

/**
 * Marry phase.
 * @author pcdejager
 */
public class MarryPhase implements PhaseExecutor {
    /**
     * Constructor.
     * @param forRace The race to marry
     */
    public MarryPhase(final String forRace) {
        race = forRace;
    }
    /**
     * Execute.
     * @param p The population to work on
     */
    public final void execute(final Population p) {
        Random random = new Random();
        double prob = RaceProperties.getInstance()
                .get(race).getRates().getMarryRate()
                / TimeProperties.getInstance().daysInAYear();
        ArrayList<Character> marryList = getPossibleList(p, prob);
        for (Character c : marryList) {
            if (c.getSocialLinks().isMarried()) {
                continue;
            }
            ArrayList<Character> available = getAvailable(p, c);
            if (available.size() < 1) {
                continue;
            }
            int index = 0;
            if (available.size() > 1) {
                index = random.nextInt(available.size());
            }
            SocialLinks.marry(c, available.get(index));
        }
    }
    /**
     * Get the list of people that must be married.
     * @param p The population
     * @param probability The probability
     * @return The list of characters
     */
    private ArrayList<Character> getPossibleList(
            final Population p,
            final double probability) {
        return p.find(
                new PopulationFindPredicate[] {
                        new FindGender(Gender.FEMALE),
                        new FindRace(race),
                        new FindRandom(probability)});
    }
    /**
     * Get the available mates for character to marry.
     * @param p The population to work with
     * @param c The character to search for
     * @return The list of available characters
     */
    private ArrayList<Character> getAvailable(
            final Population p,
            final Character c) {
        // If in love, then use love
        if (c.getSocialLinks().hasLoveInterest()) {
            // TODO : Can in future marry someone else that is not love interest
            ArrayList<Character> result = new ArrayList<Character>();
            result.add(c.getSocialLinks().getLoveInterest());
            return result;
        }
        Race r = RaceProperties.getInstance().get(race);

        int start = r.getPartner().getPartnerMinimumAge(c.getAge().years());
        int end = r.getPartner().getPartnerMaximumAge(c.getAge().years());

        // TODO : For now same sex couples not catered for
        return p.find(
                new PopulationFindPredicate[] {
                        new FindGender(Gender.MALE),
                        new FindRace(race),
                        new FindSocialLink(
                                FindSocialLink.Link.MARRIED,
                                FindSocialLink.Condition.DOESNOTEXIST),
                        new FindAgeRange(start, end),
                        new FindAllButSpecificCharacter(c)});
    }
    /**
     * The race to marry.
     */
    private final String race;
}
